/**
 * @file       godemool/decoder.h
 * @brief      Demo messages decoder.
 * @author     ben "boin" bonoeil
 * @date       2015-02
 */

/* Copyright (c) 2007-2015, ben "boin" bonoeil */

#ifndef GODEMOOL_DECODER_H
#define GODEMOOL_DECODER_H

#include "godemool/bitstream.h"
#include "godemool/hl2demo.h"
#include "godemool/codec.h"
#include "godemool/strpool.h"

namespace boin {
  class Decoder;
}

class boin::Decoder : public boin::BitStream
{

public:
  struct EventKey {
    EventKey(uint8_t t, const char *n) : type(t), name(n) {}
    uint8_t type;
    wetstring name;
  };

  typedef std::vector<EventKey> EventKeys;

  struct EventDesc {
    EventDesc() : id(-1), name(nullptr) {}
    EventDesc(uint16_t i, wetstring n) : id(i), name(n) {}
    uint16_t id;     // event id is the position in EventList.
    wetstring name;  // string pointer in the string pool
    EventKeys keys;  // List of keys for the event
  };

  typedef std::vector<EventDesc> EventList;

  /* cVars */
  struct CVar {
    CVar(wetstring n, wetstring v) : name(n), value(v) {}
    wetstring name;
    wetstring value;
  };
  typedef std::vector<CVar> CVars;
  CVars cVars;

  /* Server Info */
  struct ServerInfo {
    ServerInfo (): is_set(false) {};
    bool is_set;
    struct {
      uint32_t crc;
      wetstring name;
    } map;
    wetstring gamedir;
    uint16_t tickrate;
    uint16_t protocol;
  };
  ServerInfo srvinfo;

protected:
  StringPool strpool;
  EventList events;

public:
  bool eof;

  Decoder();
  ~Decoder();

  CodecType * Decode(Hl2Demo::Chunk & chunk);

  const EventDesc * GetEvent(uint32_t id) {
    assert(id < events.size());
    assert(events[id].id == uint16_t(-1) || id == events[id].id);
    return id == events[id].id ? &events[id] : nullptr;
  }

protected:
  void DecodeSkipAll();

  /* Raw data */
  RawData rawdata;
  void DecodeRawData(RawData & raw);

  /* Custom data */
  CustomData custom;
  void DecodeCustomData(CustomData & cdata);

  /* String tables */
  StringTables strtables;
  void DecodeStringTables(StringTables & tables);
  void DecodeStringTable(int idx, StringTable & table);
  void DecodeStringData(int idx, StringTable::String & str);

  /* Data tables */
  unsigned int classid_bits;
  DataTables dattables;
  void DecodeDataTables(DataTables & tables);

  /* Console Command */
  ConCommand concommand;
  void DecodeConCommand(ConCommand & concom);

  /* User command */
  UserCommand usrcommand;
  void DecodeUserCommand(UserCommand & usrcom);
  void SetDefault(UserCommand & usrcom);

  /* Demo/Net packets */
  Messages messages;
  void DecodeDemoPacket(Messages & msgs);
  void DecodeMessage(MsgData & mdata, const CSVCMsg_UserMessage & usr);
  void DecodeMessage(MsgData & mdata, const CSVCMsg_GameEventList & gel);
  void DecodeMessage(MsgData & mdata, const CNETMsg_SetConVar & scv);
  void DecodeMessage(MsgData & mdata, const CSVCMsg_ServerInfo & svi);

  /* Return a pointer to a clean local message */
  google::protobuf::Message * GetNetMessage(int id);
  google::protobuf::Message * GetSvcMessage(int id);
  google::protobuf::Message * GetClcMessage(int id);
  google::protobuf::Message * GetUsrMessage(int id);

  /* Primitive types */
  CMsgVector msgTyp_Vector;
  CMsgVector2D msgTyp_Vector2D;
  CMsgQAngle msgTyp_QAngle;
  CMsgRGBA msgTyp_RGBA;

  CMsg_CVars msg_CVars;
  CMsg_CVars_CVar msg_CVars_Cvar;

  /* NET_Messages [0..7] */
#define DECL_NET(NAME) CNETMsg_ ## NAME msgNet_ ## NAME
  DECL_NET(NOP);
  DECL_NET(Disconnect);
  DECL_NET(File);
  DECL_NET(SplitScreenUser);
  DECL_NET(Tick);
  DECL_NET(StringCmd);
  DECL_NET(SetConVar);
  DECL_NET(SignonState);
#undef DECL_NET

  typedef CSVCMsg_EntityMsg CSVCMsg_EntityMessage; // Somehow this one name differs !

  /* SVC_Messages [8..35]*/
#define DECL_SVC(NAME) CSVCMsg_ ## NAME msgSvc_ ## NAME
  DECL_SVC(ServerInfo);
  DECL_SVC(SendTable);
  DECL_SVC(ClassInfo);
  DECL_SVC(SetPause);
  DECL_SVC(CreateStringTable);
  DECL_SVC(UpdateStringTable);
  DECL_SVC(VoiceInit);
  DECL_SVC(VoiceData);
  DECL_SVC(Print);
  DECL_SVC(Sounds);
  DECL_SVC(SetView);
  DECL_SVC(FixAngle);
  DECL_SVC(CrosshairAngle);
  DECL_SVC(BSPDecal);
  DECL_SVC(SplitScreen);
  DECL_SVC(UserMessage);
  DECL_SVC(EntityMessage);
  DECL_SVC(GameEvent);
  DECL_SVC(PacketEntities);
  DECL_SVC(TempEntities);
  DECL_SVC(Prefetch);
  DECL_SVC(Menu);
  DECL_SVC(GameEventList);
  DECL_SVC(GetCvarValue);
  DECL_SVC(PaintmapData);
  DECL_SVC(CmdKeyValues);
  DECL_SVC(EncryptedData);
#undef DECL_SVC

  /* CLC_Messages [8..18]*/
#define DECL_CLC(NAME) CCLCMsg_ ## NAME msgClc_ ## NAME
  DECL_CLC(ClientInfo);
  DECL_CLC(Move);
  DECL_CLC(VoiceData);
  DECL_CLC(BaselineAck);
  DECL_CLC(ListenEvents);
  DECL_CLC(RespondCvarValue);
  DECL_CLC(FileCRCCheck);
  DECL_CLC(LoadingProgress);
  DECL_CLC(SplitPlayerConnect);
  /* DECL_CLC(ClientMessage); // Not defined */
  DECL_CLC(CmdKeyValues);
#undef DECL_CLC

  /* USR_Messages [1..64] */
#define DECL_USR(NAME) CCSUsrMsg_ ## NAME msgUsr_ ## NAME
  DECL_USR(VGUIMenu);
  DECL_USR(Geiger);
  DECL_USR(Train);
  DECL_USR(HudText);
  DECL_USR(SayText);
  DECL_USR(SayText2);
  DECL_USR(TextMsg);
  DECL_USR(HudMsg);
  DECL_USR(ResetHud);
  DECL_USR(GameTitle);
  DECL_USR(Shake);
  DECL_USR(Fade);
  DECL_USR(Rumble);
  DECL_USR(CloseCaption);
  DECL_USR(CloseCaptionDirect);
  DECL_USR(SendAudio);
  DECL_USR(RawAudio);
  DECL_USR(VoiceMask);
  DECL_USR(RequestState);
  DECL_USR(Damage);
  DECL_USR(RadioText);
  DECL_USR(HintText);
  DECL_USR(KeyHintText);
  DECL_USR(ProcessSpottedEntityUpdate);
  DECL_USR(ReloadEffect);
  DECL_USR(AdjustMoney);
  /* DECL_USR(UpdateTeamMoney); // Not defined */
  DECL_USR(StopSpectatorMode);
  DECL_USR(KillCam);
  DECL_USR(DesiredTimescale);
  DECL_USR(CurrentTimescale);
  DECL_USR(AchievementEvent);
  DECL_USR(MatchEndConditions);
  DECL_USR(DisconnectToLobby);
  DECL_USR(PlayerStatsUpdate);
  DECL_USR(DisplayInventory);
  DECL_USR(WarmupHasEnded);
  DECL_USR(ClientInfo);
  DECL_USR(XRankGet);
  DECL_USR(XRankUpd);
  DECL_USR(CallVoteFailed);
  DECL_USR(VoteStart);
  DECL_USR(VotePass);
  DECL_USR(VoteFailed);
  DECL_USR(VoteSetup);
  DECL_USR(ServerRankRevealAll);
  DECL_USR(SendLastKillerDamageToClient);
  DECL_USR(ServerRankUpdate);
  DECL_USR(ItemPickup);
  DECL_USR(ShowMenu);
  DECL_USR(BarTime);
  DECL_USR(AmmoDenied);
  DECL_USR(MarkAchievement);
  DECL_USR(MatchStatsUpdate);
  DECL_USR(ItemDrop);
  DECL_USR(GlowPropTurnOff);
  DECL_USR(SendPlayerItemDrops);
  DECL_USR(RoundBackupFilenames);
  DECL_USR(SendPlayerItemFound);
  DECL_USR(ReportHit);
#undef DECL_USR
};

#endif

/* Local Variables:  */
/* mode: c++         */
/* End:              */
